using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SqlTools.Utility.Windows;
using SqlTools.CodeGenerator.Data;
using schema = SqlTools.SchemaReader;
using SqlTools.CodeGenerator.UI.Controls;
using System.IO;
using System.Diagnostics;

namespace SqlTools.CodeGenerator.UI.Forms
{
	public partial class Main : Form
	{
		protected Project _project = null;

		protected bool _loading = false;
		protected ForeignKeyTablePropertyEditor _fktpEditor = null;
		protected IntrinsicTablePropertyEditor _itpEditor = null;


		public Main()
		{
			InitializeComponent();
		}

		protected void InitProject()
		{
			toolStripContainer.ContentPanel.BorderStyle = BorderStyle.None;
			tabControl.Visible = true;

			autogenToolStripButton.Enabled = true;
			autogenToolStripMenuItem.Enabled = true;
			projectToolStripMenuItem.Visible = true;

			EnableSave(true);
		}

		private void EnableSave(bool enable)
		{
			saveAsToolStripMenuItem.Enabled = enable;
			saveToolStripMenuItem.Enabled = enable;

			saveToolStripButton.Enabled = enable;
		}

		private void Save()
		{
			Save(false);
		}

		private void Save(bool choosefile)
		{
			if ( _project == null )
				return;

			string filename = "";

			if ( choosefile || string.IsNullOrEmpty(_project.Filename) )
			{
				if ( saveFileDialog.ShowDialog() == DialogResult.OK )
				{
					filename = saveFileDialog.FileName;
				}
				else
				{
					return;
				}
			}

			if ( !string.IsNullOrEmpty(filename) )
			{
				_project.Save(filename);
			}
			else
			{
				_project.Save();
			}
		}

		private void LoadProjectData()
		{
			_loading = true;

			txtConnString.Text = _project.ConnectionString;

			fdRoot.SelectedPath = _project.RootDirectory;
			fdData.SelectedPath = _project.DefaultDataDirectory;
			fdObject.SelectedPath = _project.DefaultBusinessDirectory;
			fdSQL.SelectedPath = _project.DefaultSQLDirectory;

			txtDataNamespace.Text = _project.DefaultDataNamespace;
			txtObjectNamespace.Text = _project.DefaultBusinessNamespace;
			txtConnStringName.Text = _project.DefaultConnectionStringName;
			txtSprocPrefix.Text = _project.StoredProcedurePrefix;

			txtTablePrefixes.Text = string.Join(";", _project.TablePrefixes.ToArray());

			chkAutoRunSqlScripts.Checked = _project.AutoRunSqlScripts;
			chkUseGeneratedPartialClassFormat.Checked = _project.UseGeneratedPartialClassFormat;

			PopulateTableLists();

			_loading = false;
		}

		#region ToolStripCommands
		private void new_command(object sender, EventArgs e)
		{
			_project = new Project();
			InitProject();
		}

		private void open_command(object sender, EventArgs e)
		{
			if ( openFileDialog.ShowDialog() == DialogResult.OK )
			{
				_project = new Project();
				_project.Load(openFileDialog.FileName);

				InitProject();

				LoadProjectData();
			}
		}

		private void save_command(object sender, EventArgs e)
		{
			Save();
		}

		private void saveAs_command(object sender, EventArgs e)
		{
			Save(true);
		}

		private void print_command(object sender, EventArgs e)
		{

		}

		private void autogen_command(object sender, EventArgs e)
		{
			DataHelper dh = new DataHelper(_project);

			dh.CreateTables();

			PopulateTableLists();
		}

		private void deleteTable_command(object sender, EventArgs e)
		{
			List<Table> tables = new List<Table>();
			if ( lstTables.SelectedItems.Count > 0 )
			{
				foreach ( Object obj in lstTables.SelectedItems )
				{
					Table table = obj as Table;
					if ( table != null )
					{
						_project.DeleteTable(table);
						tables.Add(table);
					}
				}
			}

			foreach ( Table table in tables )
			{
				lstTables.Items.Remove(table);
			}
		}

		private void exit_command(object sender, EventArgs e)
		{
			this.Close();
		}
		#endregion

		#region Project Info Event Handlers
		#region FolderData Event Handlers
		private void fdRoot_DirectoryChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			fdData.SelectedPath = fdRoot.SelectedPath;
			fdObject.SelectedPath = fdRoot.SelectedPath;
			fdSQL.SelectedPath = fdRoot.SelectedPath;

			_project.RootDirectory = fdRoot.SelectedPath;
		}

		private void fdData_DirectoryChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultDataDirectory = fdData.SelectedPath;
		}

		private void fdObject_DirectoryChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultBusinessDirectory = fdObject.SelectedPath;
		}

		private void fdSQL_DirectoryChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultSQLDirectory = fdSQL.SelectedPath;
		}
		#endregion

		#region Textbox Handlers
		private void txtConnString_TextChanged(object sender, EventArgs e)
		{
			btnSchemaRefresh.Enabled = ( txtConnString.Text.Trim().Length > 0 );

			if ( _loading ) return;

			_project.ConnectionString = txtConnString.Text.Trim();
		}
        //TODOS GPC add project.tables.clear for button restart
		private void txtObjectNamespace_TextChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultBusinessNamespace = txtObjectNamespace.Text;
		}

		private void txtDataNamespace_TextChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultDataNamespace = txtDataNamespace.Text;
		}

		private void txtSprocPrefix_TextChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.StoredProcedurePrefix = txtSprocPrefix.Text;
		}

		private void txtConnStringName_TextChanged(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.DefaultConnectionStringName = txtConnStringName.Text;
		}

		private void txtTablePrefixes_Leave(object sender, EventArgs e)
		{
			if ( _loading ) return;

			_project.UpdateTablePrefixes(txtTablePrefixes.Text);
		}
		#endregion

		private void btnConnect_Click(object sender, EventArgs e)
		{
			ConnectToDB connect = new ConnectToDB();

			if ( connect.ShowDialog() == DialogResult.OK )
			{
				txtConnString.Text = connect.ConnectionString;
			}
		}

		private void btnSchemaRefresh_Click(object sender, EventArgs e)
		{
			_project.Database = new SqlTools.SchemaReader.Database();

			_project.Database.LoadStoredProcedures = false;
			
			_project.Database.LoadMetadata(txtConnString.Text);

			// if we don't have any existing tables, 
			// then don't worry about the merge
			if ( _project.Tables.Count > 0 )
			{

				// now we need to update the mapping data
				// so create a duplicate project
				// and init its schema with the current
				// projects schema
				Project proj = new Project(_project);

				proj.Database = _project.Database;

				// now use datahelper to create temp mappings
				DataHelper helper = new DataHelper(proj);

				helper.CreateTables();

				ProjectMerger pm = new ProjectMerger(_project, proj);

				pm.Merge();
			}

			PopulateTableLists();
		}

		private void btnUpdateTableDirectories_Click(object sender, EventArgs e)
		{
			foreach ( Table table in _project.Tables )
			{
				table.BusinessDirectory = fdObject.SelectedPath;
				table.DataDirectory = fdData.SelectedPath;
				table.SQLDirectory = fdSQL.SelectedPath;
			}
		}

		private void btnUpdateTableDefaults_Click(object sender, EventArgs e)
		{
			foreach ( Table table in _project.Tables )
			{
				table.BusinessNamespace = txtObjectNamespace.Text;
				table.DataNamespace = txtDataNamespace.Text;
			}
		}
		#endregion

		private void tpTables_Enter(object sender, EventArgs e)
		{
			//tabTableInfo.Visible = false;

			//PopulateTableLists();
		}

		private void PopulateTableLists()
		{
			tabTableInfo.Visible = false;

			lstTables.ClearSelected();
			lstTables.Items.Clear();
			lstTables.DisplayMember = "TableName";

			cboBaseTable.SelectedItem = null;
			cboBaseTable.Items.Clear();
			cboBaseTable.DisplayMember = "TableName";

			Table[] tables = _project.Tables.ToArray();


			Array.Sort(tables, delegate(Table table1, Table table2)
				{
					return string.Compare(table1.TableName, table2.TableName);
				});

			foreach ( Table table in tables )
			{
				lstTables.Items.Add(table);
				cboBaseTable.Items.Add(table);
			}
		}

		private void lstTables_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( lstTables.SelectedIndices.Count > 0 )
			{
				if ( lstTables.SelectedIndices.Count > 1 )
				{
					SelectMultiple();
				}
				else
				{
					SelectSingle(lstTables.SelectedItem as Table);
				}

				tabTableInfo.Visible = true;
				deleteTableToolStripMenuItem.Enabled = true;
			}
			else
			{
				tabTableInfo.Visible = false;
				deleteTableToolStripMenuItem.Enabled = false;
			}
		}

		protected void SelectSingle(Table table)
		{
			_loading = true;

			lblTableName.Text = table.TableName;

			if ( table.BaseTable != null )
			{
				cboBaseTable.SelectedItem = table.BaseTable;
			}
			else
			{
				cboBaseTable.SelectedItem = null;
			}

			fdTableData.SelectedPath = table.DataDirectory;
			fdTableObject.SelectedPath = table.BusinessDirectory;
			fdTableSQL.SelectedPath = table.SQLDirectory;

			txtTableDataNamespace.Text = table.DataNamespace;
			txtTableBusinessNamespace.Text = table.BusinessNamespace;

			txtTableObjectName.Text = table.BusinessObjectName;
			txtTableDBObjectName.Text = table.DbObjectName;

			txtPrimaryKeyClassName.Text = table.PrimaryKeyClassName;
			txtPrimaryKeyFieldName.Text = table.PrimaryKeyFieldName;

			lvwProperties.Items.Clear();
			pnlPropertyData.Controls.Clear();

			foreach ( TableProperty tp in table.Properties )
			{
				ListViewItem lvi = null;

				if ( tp.Type == TablePropertyType.PrimaryKey )
				{
					PrimaryKeyTableProperty pktp = tp as PrimaryKeyTableProperty;

					foreach ( TableProperty stp in pktp.Properties )
					{
						lvi = new ListViewItem("PK, " + TypeName(stp.Type));
						lvi.SubItems.Add(stp.ColumnName);
						lvi.SubItems.Add(stp.PropertyName);
						lvi.SubItems.Add(stp.CSharpDataType);

						lvi.Tag = stp;

						lvwProperties.Items.Add(lvi);
					}
				}
				else
				{
					lvi = new ListViewItem(TypeName(tp.Type));
					lvi.SubItems.Add(tp.ColumnName);
					lvi.SubItems.Add(tp.PropertyName);
					lvi.SubItems.Add(tp.CSharpDataType);

					lvi.Tag = tp;

					lvwProperties.Items.Add(lvi);
				}

			}

			lvwMethods.Items.Clear();

			txtMethodName.Text = "";
			txtSProcName.Text = "";
			lstSourceColumns.Items.Clear();
			lstDestinationColumns.Items.Clear();


			foreach ( Method method in table.Methods )
			{
				ListViewItem lvi = new ListViewItem(method.Type.ToString());
				lvi.SubItems.Add(method.MethodName);

				string parameters = GetParameterList(method);

				lvi.SubItems.Add(parameters);
				lvi.Tag = method;
				lvwMethods.Items.Add(lvi);
			}

			_loading = false;
		}

		protected void SelectMultiple()
		{

		}

		protected string GetParameterList(Method method)
		{
			string parameters = "";

			foreach ( MethodParameter mp in method.Parameters )
			{
				if ( parameters.Length > 0 ) parameters += ", ";

				parameters += mp.ParameterName;
			}

			return parameters;
		}

		protected string TypeName(TablePropertyType type)
		{
			switch ( type )
			{
				case TablePropertyType.ForeignKey:
					return "FK";
				case TablePropertyType.PrimaryKey:
					return "PK";
				case TablePropertyType.Intrinsic:
					return "ITP";
			}

			return "";
		}

		private void lvwProperties_SelectedIndexChanged(object sender, EventArgs e)
		{
			pnlPropertyData.Controls.Clear();

			if ( lvwProperties.SelectedItems.Count > 0 )
			{
				TableProperty tp = lvwProperties.SelectedItems[0].Tag as TableProperty;

				if ( tp != null )
				{
					if ( tp.Type == TablePropertyType.ForeignKey )
					{
						if ( _fktpEditor == null )
							_fktpEditor = new ForeignKeyTablePropertyEditor();

						_fktpEditor.Project = _project;
						_fktpEditor.CurrentTable = lstTables.SelectedItem as Table;
						_fktpEditor.Property = tp as ForeignKeyTableProperty;

						// shouldn't be anything else in there
						pnlPropertyData.Controls.Clear();

						pnlPropertyData.Controls.Add(_fktpEditor);
						_fktpEditor.Dock = DockStyle.Fill;
					}
					else
					{
						if ( _itpEditor == null )
							_itpEditor = new IntrinsicTablePropertyEditor();

						_itpEditor.Property = tp;

						// shouldn't be anything else in there
						pnlPropertyData.Controls.Clear();

						pnlPropertyData.Controls.Add(_itpEditor);
						_itpEditor.Dock = DockStyle.Fill;
					}
				}
			}
		}

		private void lvwMethods_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( lvwMethods.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				txtMethodName.Text = method.MethodName;
				txtSProcName.Text = method.StoredProcedureName;

				lstSourceColumns.Items.Clear();
				lstSourceColumns.DisplayMember = "Name";
				lstDestinationColumns.Items.Clear();
				lstDestinationColumns.DisplayMember = "ColumnName";

				schema.Table stable = _project.Database.Tables[method.Table.TableName];
				foreach ( schema.Column scolumn in stable.Columns )
				{
					lstSourceColumns.Items.Add(scolumn);
				}

				foreach ( MethodParameter mp in method.Parameters )
				{
					if ( mp.Property.Type != TablePropertyType.PrimaryKey )
					{
						lstDestinationColumns.Items.Add(mp.Property);
						lstSourceColumns.Items.Remove(stable.Columns[mp.Property.ColumnName]);
					}
				}
			}
			else
			{
				txtMethodName.Text = "";
				txtSProcName.Text = "";
				lstSourceColumns.Items.Clear();
				lstDestinationColumns.Items.Clear();
			}
		}

		private void btnAddColumn_Click(object sender, EventArgs e)
		{
			if ( lstSourceColumns.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				if ( method == null )
					return;

				List<schema.Column> remove = new List<SqlTools.SchemaReader.Column>();
				foreach ( Object obj in lstSourceColumns.SelectedItems )
				{
					schema.Column scolumn = obj as schema.Column;
					remove.Add(scolumn);

					MethodParameter mp = new MethodParameter(NamingHelper.ClassVariableName(scolumn.Name), method, method.Table.Properties.FindPropertyByColumnName(scolumn.Name));
					method.Parameters.Add(mp);
					lstDestinationColumns.Items.Add(mp.Property);
				}

				lvwMethods.SelectedItems[0].SubItems[2].Text = GetParameterList(method);
			}
		}

		private void btnRemoveColumn_Click(object sender, EventArgs e)
		{
            // TODOS GPC add update to clear items
			if ( lstDestinationColumns.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				if ( method == null )
					return;

				List<TableProperty> remove = new List<TableProperty>();
				foreach ( Object obj in lstDestinationColumns.SelectedItems )
				{
					TableProperty tp = obj as TableProperty;

					MethodParameter parm = null;
					foreach ( MethodParameter mp in method.Parameters )
					{
						if ( mp.Property == tp )
						{
							parm = mp;
							break;
						}
					}
					method.Parameters.Remove(parm);


					schema.Table stable = _project.Database.Tables[method.Table.TableName];
					schema.Column scolumn = stable.Columns[parm.Property.ColumnName];

					lstSourceColumns.Items.Add(scolumn);
				}

				lvwMethods.SelectedItems[0].SubItems[2].Text = GetParameterList(method);
			}
		}

		private void txtMethodName_TextChanged(object sender, EventArgs e)
		{
			if ( lvwMethods.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				method.MethodName = txtMethodName.Text;
				lvwMethods.SelectedItems[0].SubItems[1].Text = txtMethodName.Text;
			}
		}

		private void txtSProcName_TextChanged(object sender, EventArgs e)
		{
			if ( lvwMethods.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				method.StoredProcedureName = txtSProcName.Text;
			}
		}

		private void btnDelete_Click(object sender, EventArgs e)
		{
			if ( lvwMethods.SelectedItems.Count > 0 )
			{
				Method method = lvwMethods.SelectedItems[0].Tag as Method;

				method.Table.Methods.Remove(method);
				lvwMethods.Items.Remove(lvwMethods.SelectedItems[0]);
			}
		}

		private void btnAdd_Click(object sender, EventArgs e)
		{
			Table table = lstTables.SelectedItems[0] as Table;

			Method method = new Method("New Method", lstTables.SelectedItems[0] as Table, MethodType.SelectMultiple);

			ListViewItem lvi = new ListViewItem(method.Type.ToString());
			lvi.SubItems.Add(method.MethodName);

			string parameters = GetParameterList(method);

			lvi.SubItems.Add(parameters);
			lvi.Tag = method;

			lvwMethods.Items.Add(lvi);
			table.Methods.Add(method);

			lvi.Selected = true;
		}

		private void generateFiles_command(object sender, EventArgs e)
		{
			this.UseWaitCursor = true;
			toolStripProgressBar.Visible = true;
			backgroundWorker.RunWorkerAsync();

		}

		private void cboBaseTable_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( _loading || lstTables.SelectedItems.Count == 0 )
				return;

            // TODOS GPC add table driven method to update changed text fields.
			Table table = lstTables.SelectedItems[0] as Table;

			if ( cboBaseTable.SelectedItem is Table )
			{

				table.BaseTable = cboBaseTable.SelectedItem as Table;
			}
			else
			{
                           
				table.BaseTable = null;
			}
		}

		private void chkAutoRunSqlScripts_CheckedChanged(object sender, EventArgs e)
		{
			_project.AutoRunSqlScripts = chkAutoRunSqlScripts.Checked;
		}

		private void chkUseGeneratedPartialClassFormat_CheckedChanged(object sender, EventArgs e)
		{
			_project.UseGeneratedPartialClassFormat = chkUseGeneratedPartialClassFormat.Checked;
		}

		private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
		{
			_project.GenerateCode(backgroundWorker);
		}

		private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			toolStripProgressBar.Value = e.ProgressPercentage;
			Application.DoEvents();

		}

		private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			toolStripProgressBar.Value = 0;
			this.UseWaitCursor = false;
			toolStripProgressBar.Visible = false;

			MessageBox.Show("All files have been successfully generated", "Operation Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void tabTableInfo_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void txtTableDataNamespace_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.DataNamespace = txtTableDataNamespace.Text;
        }

        private void txtTableObjectName_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.BusinessObjectName = txtTableObjectName.Text;

        }

      



        private void txtTableBusinessNamespace_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.BusinessNamespace = txtTableBusinessNamespace.Text;

        }

        private void txtTableDBObjectName_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.DbObjectName = txtTableDBObjectName.Text;

        }

        private void txtPrimaryKeyClassName_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.PrimaryKeyClassName = txtPrimaryKeyClassName.Text;

        }

        private void txtPrimaryKeyFieldName_TextChanged(object sender, EventArgs e)
        {
            if (_loading || lstTables.SelectedItems.Count == 0)
                return;
            Table table = lstTables.SelectedItems[0] as Table;
            table.PrimaryKeyFieldName = txtPrimaryKeyFieldName.Text;

        }
	}
}
